public class Principal {
	private static final long tempoMaximo = 100000, tempoMinimo = 5;
	private static final int repeticions = 100, anchura = 18;
	private static Crono crono = new Crono();
	private static int filas;
	private static int nInicial = 20;
	private static int salto = 2;

	private static void imprimeLina(int i) {
		for (int j = 0; j < i; j++)
			System.out.print("-");
		System.out.println();
	}

	private static void imprimeMatrizCadrada(int[][] matriz) {
		for (int i = 0; i < matriz.length; i++) {
			System.out.print("(");
			for (int j = 0; j < matriz.length; j++) {
				System.out.print(" " + matriz[i][j]);
			}
			System.out.println(" )");
		}
	}

	private static void executa(int[][] mAdyacencia) {
		int[][] v = CaminosMinimos.caminosMinimos(mAdyacencia);
		imprimeMatrizCadrada(v);
	}

	private static void proba() {
		int[][] grafo1 = { { 0, 1, 8, 4, 7 }, { 1, 0, 2, 6, 5 }, { 8, 2, 0, 9, 5 }, { 4, 6, 9, 0, 3 }, { 7, 5, 5, 3, 0 } };
		int[][] grafo2 = { { 0, 1, 4, 7 }, { 1, 0, 2, 8 }, { 4, 2, 0, 3 }, { 7, 8, 3, 0 } };
		// GRAFO1
		System.out.println("Grafo 1, con Matriz de adyacencia:");
		imprimeMatrizCadrada(grafo1);
		System.out.println("Matriz de distancias minimas:");
		executa(grafo1);

		// GRAFO2
		System.out.println("\nGrafo 2, con Matriz de adyacencia:");
		imprimeMatrizCadrada(grafo2);
		System.out.println("Matriz de distancias minimas:");
		executa(grafo2);
	}

	private static double[] avaliar(InicializacionMatrices ini) {

		filas = 6; 	// En principio, faranse 'filas' iteracions (se non se
					// supera o tempo maximo)

		double[] tempo = new double[filas];
		int[][] m;

		for (int n = nInicial, indice = 0; indice < filas; n *= salto, indice++) {
			m = new int[n][n];
			ini.inicializar(m);

			// * Tempos para calcular os caminhos minimos *//
			crono.iniciar();
			CaminosMinimos.caminosMinimos(m);
			tempo[indice] = crono.tiempo();

			// * Para tempos menores a 'tempoMinimo' *//
			if (tempo[indice] < tempoMinimo) {

				crono.iniciar();
				for (int j = 0; j < repeticions; j++) {
					CaminosMinimos.caminosMinimos(m);
				}
				long aux = crono.tiempo();

				tempo[indice] = -aux / (double) repeticions;
			}

			if (Math.abs(tempo[indice]) > tempoMaximo) {
				filas = indice;
				break;
			}
		}

		return (tempo);
	}

	private static void analise(InicializacionMatrices ini, double[] tempo) {

		System.out.println();
		System.out.println("\nCalculo de " + new CaminosMinimos().toString() + " con " + ini.toString() + "\n");
		System.out.print(Format.format("n", anchura - 10, true));
		System.out.print(Format.format("m", anchura - 10, true));
		System.out.print(Format.format("T(n)", anchura - 5, false));
		System.out.print(Format.format("T(n)/n^2", anchura, false));
		System.out.print(Format.format("T(n)/((m+n)*log(n))", anchura+5, false));
		System.out.print(Format.format("T(n)/n^3", anchura, false));
		System.out.println(Format.format("T(n)/n^4", anchura, false));


		imprimeLina(7 * anchura - 10);

		// n = numero de nodos
		// m = numero de aristas
		for (int n = nInicial, indice = 0; indice < filas; n *= salto, indice++) {
			int m = n*(n-1)/2;
			System.out.print(Format.format(String.valueOf(n), anchura - 10, true));
			System.out.print(Format.format(String.valueOf(m), anchura - 10, true));
			System.out.print(Format.format(Math.abs(tempo[indice]), anchura - 6, anchura - 14) + ((tempo[indice] <= 0) ? '*' : ' '));

			tempo[indice] = Math.abs(tempo[indice]);

			System.out.print(Format.format(tempo[indice] / Math.pow(n,2), anchura, anchura - 7));
			System.out.print(Format.format(tempo[indice] / ((m+n)*Math.log(n)), anchura+5, anchura - 7));
			System.out.print(Format.format(tempo[indice] / Math.pow(n, 3), anchura, anchura - 7));
			System.out.println(Format.format(tempo[indice] / Math.pow(n, 4), anchura, anchura - 7));

		}
		imprimeLina(7 * anchura - 10);
		System.out.println("(*) Empregouse un bucle de " + repeticions + " iteracions. O tempo reflectido corresponde a unha iteracion");
		System.out.println("Todolos tempos en milisegundos");
	}

	public static void main(String[] args) {
	 proba();
		
		analise(new MatrizAleatoria(), avaliar(new MatrizAleatoria()));

	}
}
